package com.cupdata.zicon.jdk7concurrent.chapter2;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

/**
 * A classic problem in concurrent programming is the producer-consumer problem.
 * We have a data buffer, one or more producers of data that save it in the
 * buffer and one or more consumers of data that take it from the buffer. As the
 * buffer is a shared data structure, we have to control the access to it using
 * a synchronization mechanism such as the synchronized keyword, but we have
 * more limitations. A producer can't save data in the buffer if it's full and
 * the consumer can't take data from the buffer if it's empty.
 * 
 * 
 * A thread can call the wait() method inside a synchronized block of code. If
 * it calls the wait() method outside a synchronized block of code, the JVM
 * throws an IllegalMonitorStateException exception. When the thread calls the
 * wait() method, the JVM puts the thread to sleep and releases the object that
 * controls the synchronized block of code that it's executing and allows the
 * other threads to execute other blocks of synchronized code protected by that
 * object. To wake up the thread, you must call the notify() or notifyAll()
 * method inside a block of code protected by the same object.
 * 
 * You have to keep checking the conditions and calling the wait() method
in a while loop. You can't continue until the condition is true.
 * 
 * 
 * @author SunYabing
 *
 */
public class UseConditionsInSynchronizedCodeTest {

	//@Test
	public static void main(String[] args) {
		
		EventStorage storage=new EventStorage();
		
		Producer producer=new Producer(storage);
		Thread thread1=new Thread(producer);
		Thread thread3=new Thread(producer);
		
		Consumer consumer=new Consumer(storage);
		Thread thread2=new Thread(consumer);
		Thread thread4=new Thread(consumer);
		
		
		
		
			
			
		thread2.start();
		thread1.start();
//		thread3.start();
//		thread4.start();
		}
	

}

class EventStorage {
	private int maxSize;
	private  List<Date> storage;

	public EventStorage() {
		maxSize = 100;
		storage = new LinkedList<>();
	}

	public synchronized void set() {
		while (storage.size() == maxSize) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		((LinkedList<Date>) storage).add(new Date());
		System.out.printf("Set: %d \n", storage.size());
		notifyAll();
	}

	public synchronized void get() {
		while (storage.size() == 0) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			System.out.printf("Get: %d: %s \n", storage.size(),
					((LinkedList<?>) storage).getFirst());
			notifyAll();
		}
	}

}

class Producer implements Runnable {
	private EventStorage storage;

	public Producer(EventStorage storage) {
		this.storage = storage;
	}

	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			storage.set();
		}
	}
}

class Consumer implements Runnable {
	private EventStorage storage;

	public Consumer(EventStorage storage) {
		this.storage = storage;
	}

	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			storage.get();
		}
	}
}
